package com.anlogic.sdk.utils.options;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import org.apache.logging.log4j.Logger;

import com.anlogic.sdk.utils.FileUtils;
import com.anlogic.sdk.utils.LogUtils;

public enum ChipType {
	DR1M90("dr1m90", "dr1m90"), DR1V90("dr1v90", "dr1v90"), PH1P35("ph1p35", "ph1p35"), PH1P50("ph1p50", "ph1p50"), DR1M350("dr1m350", "dr1m350"), SOC66080("soc66080", "soc66080");
	
	private static Logger logger = LogUtils.getLogger(ChipType.class);
	
	private String id;

	private String name;

	private boolean visible = true;

	private static Map<String, ChipType> idMap = new LinkedHashMap<>();

	private static Map<String, ChipType> nameMap = new LinkedHashMap<>();

	private static List<ChipType> chipValues = new ArrayList<>();

	static {
		Properties prop = new Properties();
		InputStream input = null;
		try {
			String path = FileUtils.getPluginResourcePath("com.anlogic.sdk.utils", "chip.properties");
		    input = new FileInputStream(path);
		    prop.load(input);
		} catch (Exception e) {
			logger.error("Load chip properties error: {}", e.getMessage());
		} finally {
		    if (input != null) {
		        try {
		            input.close();
		        } catch (IOException e) {
		        	logger.error("Load chip properties error: {}", e.getMessage());
		        }
		    }
		}

		for (ChipType chip : ChipType.values()) {
			String isVisiable = prop.getProperty(chip.getName());
			if (isVisiable != null && isVisiable.equals("false")) {
				chip.setVisiable(false);
			}
			if (chip.isVisiable()) {
				idMap.put(chip.getId(), chip);
				nameMap.put(chip.getName(), chip);
				chipValues.add(chip);
			}
		}
	}
	
	ChipType(String id, String name) {
		this.id = id;
		this.name = name;
	}

	public String getId() {
		return this.id;
	}

	public String getName() {
		return this.name;
	}

	public boolean isVisiable() {
		return this.visible;
	}
	
	public void setVisiable(boolean visible) {
		this.visible = visible;
	}

	public static String[] getIds() {
		return idMap.keySet().toArray(new String[0]);
	}

	public static String[] getNames() {
		return nameMap.keySet().toArray(new String[0]);
	}

	public static List<ChipType> getValues() {
		return chipValues;
	}

	public static ChipType getDefault() {
		if (chipValues.isEmpty()) {
			return null;
		}
		return chipValues.get(0);
	}

	public static ChipType getTypeById(String id) {
		return idMap.get(id);
	}

	public static ChipType getTypeByName(String name) {
		return nameMap.get(name);
	}

	public static boolean isValid(String name) {
		if (nameMap.containsKey(name) && nameMap.get(name).isVisiable()) {
			return true;
		}
		return false;
	}

	public static String[] linuxSupported() {
		List<String> list = new ArrayList<>();
		if (isValid(DR1M90.getName())) {
			list.add(DR1M90.getName());
		}
		if (isValid(DR1V90.getName())) {
			list.add(DR1V90.getName());
		}
		if (isValid(SOC66080.getName())) {
			list.add(SOC66080.getName());
		}
		if (isValid(DR1M350.getName())) {
			list.add(DR1M350.getName());
		}
		return list.toArray(new String[0]);
	}
	
	public static List<CpuType> getCpuList(String name) {
		List<CpuType> list = new ArrayList<>();
		if (name.equals(DR1M90.getName())) {
			list.add(CpuType.A35_0);
			list.add(CpuType.A35_1);
		} else if (name.equals(SOC66080.getName()) || name.equals(DR1M350.getName())) {
			list.add(CpuType.A53_0);
			list.add(CpuType.A53_1);
			list.add(CpuType.A53_2);
			list.add(CpuType.A53_3);
		} else if (name.equals(DR1V90.getName()) || isPh1p(name)) {
			list.add(CpuType.RPU);
		}
		return list;
	}

	public static CpuType getDefaultCpu(String name) {
		if (name.equals(DR1M90.getName())) {
			return CpuType.A35_0;
		} else if (name.equals(SOC66080.getName()) || name.equals(DR1M350.getName())) {
			return CpuType.A53_0;
		} else if (name.equals(DR1V90.getName()) || isPh1p(name)) {
			return CpuType.RPU;
		}
		return null;
	}

	public static String[] getCpuNames(String name) {
		List<CpuType> list = getCpuList(name);
		List<String> names = new ArrayList<String>();
		for (CpuType cpu : list) {
			names.add(cpu.getName());
		}
		return names.toArray(new String[0]);
	}
	
	public static List<String> getBitWidthList(String name, String os) {
		List<String> list = new ArrayList<>();
		if (name.equals(DR1M90.getName())) {
			list.add(BitWidth.BIT64.getName());
			if (OsType.isStandalone(os)) {
				list.add(BitWidth.BIT32.getName());
			}
		} else if (name.equals(SOC66080.getName()) || name.equals(DR1M350.getName())) {
			list.add(BitWidth.BIT64.getName());
		} else if (name.equals(DR1V90.getName())) {
			list.add(BitWidth.BIT64.getName());
		} else if (isPh1p(name)) {
			list.add(BitWidth.BIT32.getName());
		}
		return list;
	}

	public static List<ArchType> getArchList(String name) {
		List<ArchType> list = new ArrayList<>();
		if (name.equals(DR1M90.getName())) {
			list.add(ArchType.AArch64);
			list.add(ArchType.AArch32);
		} else if (name.equals(SOC66080.getName()) || name.equals(DR1M350.getName())) {
			list.add(ArchType.AArch64);
			//list.add(ArchType.AArch32);
		} else if (name.equals(DR1V90.getName()) || isPh1p(name)) {
			list.add(ArchType.RISCV);
		}
		return list;
	}

	public static ArchType getArch(String name, String bitWidth) {
		if (isArm(name)) {
			if (bitWidth.equals(BitWidth.BIT64.getName())) {
				return ArchType.AArch64;
			} else if (bitWidth.equals(BitWidth.BIT32.getName())) {
				return ArchType.AArch32;
			}
		} else if (isRiscv(name)) {
			return ArchType.RISCV;
		}
		return null;
	}

	public static String[] getArchNames(String name) {
		List<ArchType> list = getArchList(name);
		List<String> names = new ArrayList<String>();
		for (ArchType tmp : list) {
			names.add(tmp.getName());
		}
		return names.toArray(new String[0]);
	}

	public static boolean isAArch64(String name) {
		if (name.equals(DR1M90.getName()) || name.equals(SOC66080.getName()) || name.equals(DR1M350.getName())) {
			return true;
		}
		return false;
	}

	public static boolean isArm(String name) {
		if (name.equals(DR1M90.getName()) || name.equals(SOC66080.getName()) || name.equals(DR1M350.getName())) {
			return true;
		}
		return false;
	}

	public static boolean isRiscv(String name) {
		if (name.equals(DR1V90.getName()) || isPh1p(name)) {
			return true;
		}
		return false;
	}

	public static boolean isDr1m90(String name) {
		return name.equals(DR1M90.getName());
	}

	public static boolean isDr1v90(String name) {
		return name.equals(DR1V90.getName());
	}

	public static boolean isDr1(String name) {
		return name.equals(DR1M90.getName()) || name.equals(DR1V90.getName());
	}

	public static boolean isPh1p35(String name) {
		return name.equals(PH1P35.getName());
	}
	
	public static boolean isPh1p50(String name) {
		return name.equals(PH1P50.getName());
	}
	
	public static boolean isPh1p(String name) {
		return (name.equals(PH1P35.getName()) || name.equals(PH1P50.getName()));
	}
	
	public static boolean isSOC66080(String name) {
		return name.equals(SOC66080.getName());
	}
	
	public static boolean isDR1M350(String name) {
		return name.equals(DR1M350.getName());
	}
}
